﻿#include "widgetpointview.h"
#include "Public/appsignal.h"
#include "Log/logger.h"

#include <QFileDialog>
#include <QWheelEvent>
#include <QtMath>
#include <QPainter>
#include <QDateTime>

// grid label point highpoint line

WidgetPointView::WidgetPointView(QWidget *parent)
    : QOpenGLWidget{parent}
{
    init();
}

void WidgetPointView::focusProp()
{
    QRectF rect = boundingRect();
    if ((rect.width() == 0) || (rect.height() == 0)) return;
    mXOffset = (rect.x() + rect.width() * 0.5) * -1;
    mYOffset = (rect.y() + rect.height() * 0.5) * -1;
    mViewZoom = mBaseZoomLength / qMax(rect.width(), rect.height()) * 0.9;

    update();
    //qDebug() << "offset " << rect << mXOffset << mYOffset;
}

void WidgetPointView::deleteSelectPoint()
{
    int pointNumber = mPointList.length();
    for (int i = 0; i < pointNumber; i++)
    {
        if (!mPointList.value(i).valid())
        {
            mPointList[i].setValid(false);
            continue;
        }
        if (!mPointList.value(i).highlight()) continue;
        mPointList[i].setHighlight(false);
        mPointList[i].setValid(false);
    }
    update();
}

void WidgetPointView::restorePreviousDelete()
{
    int pointNumber = mPointList.length();
    for (int i = 0; i < pointNumber; i++)
    {
        if (mPointList.value(i).valid()) continue;
        mPointList[i].setValid(true);
    }
    update();
}

void WidgetPointView::exportPoint()
{
    int len = mPointList.size();
    int vn = 0;
    for (int i = 0; i < len; i++)
    {
        if (mPointList.value(i).valid()) vn++;
    }

    if (vn == 0)
    {
        LOG_DEBUG("没有找到有效数据");
        emit AppSignal::getInstance()->sgl_occur_system_error("没有找到有效数据");
        return;
    }

    QString fileName = QFileDialog::getSaveFileName(this, "保存文件", "", "文本文件 (*.txt)");
    if (fileName.isEmpty()) return;
    mCustomFileParser.exportPointData(fileName, mPointList);
}

void WidgetPointView::clear()
{
    mPointList.clear();
    mOriginPointDerail = {"", 0, 0, 0, 0};
    mViewZoom = 1;
    mBaseZoomLength = 1.0;
    mXOffset = 0;
    mYOffset = 0;
    mSelectMode = false;
    mShowLineStatues = false;
    mPointMode = 0;

    update();
}

void WidgetPointView::init()
{
    // 抗锯齿
    QSurfaceFormat surfaceFormat;
    surfaceFormat.setSamples(24);
    setFormat(surfaceFormat);

    connect(AppSignal::getInstance(), &AppSignal::sgl_parse_file_result, this, &WidgetPointView::slot_parse_file_result);
    connect(AppSignal::getInstance(), &AppSignal::sgl_parse_tiff_result, this, &WidgetPointView::slot_parse_tiff_result);
}

void WidgetPointView::initializeGL()
{
    // 着色器文件不能使用 UTF-8-BOM 编码，会报错，只能采用 UTF-8 编码

    // 加载顶点着色器
    bool status = mShaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Resource/shader/shader.vert");
    if (!status)
    {
        LOG_DEBUG(QString("parse vertex shader fail ").arg(mShaderProgram.log()).toStdString());
        return;
    }

    // 加载片段着色器
    status= mShaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/Resource/shader/shader.frag");
    if (!status)
    {
        LOG_DEBUG(QString("parse fragment shader fail ").arg(mShaderProgram.log()).toStdString());
        return;
    }

    // 链接程序
    mShaderProgramLinked = mShaderProgram.link();
    if (!mShaderProgramLinked)
    {
        LOG_DEBUG(QString("link shader fail ").arg(mShaderProgram.log()).toStdString());
        return;
    }

    // 不调用这句话，就不能使用 gl 开头的函数，程序会崩溃
    initializeOpenGLFunctions();

    // 画 纹理 （图片）
    {
        glUseProgram(mShaderProgram.programId());

        glGenVertexArrays(7, mVAOArray);
        glGenBuffers(7, mVBOArray);
        glGenBuffers(3, mEBOArray);

        glGenTextures(1, &mTextureID);

        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glEnable(GL_BLEND);
    }

    mTextureWidth = 1000;
    mTextureHeight = 1000;

    LOG_DEBUG(QString("opengl init success . ").toStdString());
}

void WidgetPointView::resizeGL(int w, int h)
{
    if (!mShaderProgramLinked) return;

    if (w <= 0) w = 1;
    if (h <= 0) h = 1;

    double rate = (double)mTextureHeight / mTextureWidth;
    if (w > h)
    {
        mTextureWidth = w;
        mTextureHeight = w / rate;
    }
    else
    {
        mTextureWidth = h * rate;
        mTextureHeight = h;
    }
    if (mViewZoom == 1)
    {
        QPointF p1 = mapToOpenGL(QPointF(0, 0));
        QPointF p2 = mapToOpenGL(QPointF(width(), height()));
        mBaseZoomLength = qMin(qAbs(p2.x() - p1.x()), qAbs(p2.y() - p1.y()));
    }
    update();
}

void WidgetPointView::paintGL()
{
    if (!mShaderProgramLinked) return;
    glViewport((width() - mTextureWidth) / 2.0, (height() - mTextureHeight) / 2.0, mTextureWidth, mTextureHeight);
    glClearColor(0.976f, 0.964f, 0.925f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    // 判断是否绘制网格
    QMatrix4x4 matrix;
    matrix.setToIdentity();
    matrix.scale(mViewZoom, mViewZoom, 1);
    matrix.translate(mXOffset, mYOffset);
    mShaderProgram.setUniformValue("transform", matrix);

    // 网格
    if (mShowGridStatues) drawGrid();

    // 底图
    if (mShowTiffStatues) drawTiff();

    // 网格文本
    if (mShowGridStatues) drawLabels();

    // 绘制点云
    drawPoint();

    // 绘制高亮点
    drawHighlightPoint();

    // 绘制线
    if (mShowLineStatues) drawLine();

    // 判断是否绘制 框选
    drawBox();
}

void WidgetPointView::wheelEvent(QWheelEvent *event)
{
    int delta = event->angleDelta().y();
    float scaleFactor = (delta > 0) ? 1.1f : 0.9f;
    mViewZoom *= scaleFactor;
    update();
}

void WidgetPointView::mousePressEvent(QMouseEvent *event)
{
    if (event->button() != Qt::LeftButton) return;
    mLastMousePosition = event->localPos();
    mMousePressed = true;
}

void WidgetPointView::mouseMoveEvent(QMouseEvent *event)
{
    if (!mMousePressed) return;
    if (!event->buttons().testFlag(Qt::LeftButton)) return;
    if (mSelectMode)
    {
        mCurrentMousePosition = event->localPos();
        update();
        return;
    }

    QPointF delta = event->localPos() - mLastMousePosition;

    mXOffset += ((double)delta.x() * 2 / (mTextureWidth * mViewZoom));
    mYOffset -= ((double)delta.y() * 2 / (mTextureHeight * mViewZoom));

    // Update mouse press position for next move event
    mLastMousePosition = event->localPos();

    update();
}

void WidgetPointView::mouseReleaseEvent(QMouseEvent *event)
{
    mMousePressed = false;
    event->accept();

    // 高亮选中的点
    if (mSelectMode) highlightPoint();
    update();
}

void WidgetPointView::keyPressEvent(QKeyEvent *event)
{
    event->accept();
    if (event->isAutoRepeat()) return;
    if (event->key() == Qt::Key_Space)
    {
        // 修改鼠标样式
        setCursor(Qt::CrossCursor);
        // 切换为框选模式
        mSelectMode = true;
    }
    else if (event->key() == Qt::Key_D)
    {
        // 删除选中的点
        deleteSelectPoint();
    }
    else if (event->key() == Qt::Key_Z)
    {
        // 取消上一次的删除
        restorePreviousDelete();
    }
}

void WidgetPointView::keyReleaseEvent(QKeyEvent *event)
{
    event->accept();
    if (event->isAutoRepeat()) return;
    if (event->key() == Qt::Key_Space)
    {
        // 修改鼠标样式
        setCursor(Qt::ArrowCursor);
        // 切换为常规模式
        mSelectMode = false;
        update();
    }
}

void WidgetPointView::drawGrid()
{
    mShaderProgram.setUniformValue("u_Color", 0.725f, 0.709f, 0.674f, 1);
    glBindVertexArray(mVAOArray[0]);
    glEnableVertexAttribArray(0);

    QPointF p1 = mapToOpenGL(QPointF(0, 0));
    QPointF p2 = mapToOpenGL(QPointF(width(), height()));

    float width = p2.x() - p1.x();
    float height = p2.y() - p1.y();

    //qDebug() << "length " << QString::number(width, 'f', 20) << QString::number(height, 'f', 20);

    float space = qRound(qLn(width / 20.0) / qLn(5));
    space = qPow(5, space);

    int gridSize = (int)qAbs(width / space) + (int)qAbs(height / space) + 2;
    int pointNumber = gridSize * 2 * 2;

    // 计算网格位置
    float *vertices = new float[3 * pointNumber];
    float xPos = qCeil(p1.x() / space) * space;
    float yPos = qCeil(p1.y() / space) * space;
    //qDebug() << "grid space " << space << xPos << yPos << gridSize << qAbs(width / space) << qAbs(height / space);
    for (int i = 0; i < pointNumber; i++)
    {
        vertices[i * 3] = xPos;
        vertices[i * 3 + 1] = p2.y();
        vertices[i * 3 + 2] = -0.5;
        i++;

        vertices[i * 3] = xPos;
        vertices[i * 3 + 1] = p1.y();
        vertices[i * 3 + 2] = -0.5;
        i++;

        vertices[i * 3] = p1.x();
        vertices[i * 3 + 1] = yPos;
        vertices[i * 3 + 2] = -0.5;
        i++;

        vertices[i * 3] = p2.x();
        vertices[i * 3 + 1] = yPos;
        vertices[i * 3 + 2] = -0.5;

        xPos = xPos + space;
        yPos = yPos - space;
    }

    glBindBuffer(GL_ARRAY_BUFFER, mVBOArray[0]);
    glBufferData(GL_ARRAY_BUFFER, pointNumber * 3 * 4, vertices, GL_DYNAMIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);

    glLineWidth(1);
    glDrawArrays(GL_LINES, 0, pointNumber);
    glDisableVertexAttribArray(0);

    delete [] vertices;
}

void WidgetPointView::drawTiff()
{
    if (!mTiffDetail.valid) return;
    QImage image = mTiffDetail.image;

    QPointF p1 = {mTiffDetail.topleftx - mOriginPointDerail.x(mPointMode),  mTiffDetail.toplefty - mOriginPointDerail.y(mPointMode)};
    QPointF p2 = {mTiffDetail.bottomrightx - mOriginPointDerail.x(mPointMode),  mTiffDetail.bottomrighty - mOriginPointDerail.y(mPointMode)};

    // 计算网格位置
    float vertices[] =
    {
        (float)p1.x(), (float)p1.y(), -1.0f, 0.0f, 0.0f,
        (float)p2.x(), (float)p1.y(), -1.0f, 1.0f, 0.0f,
        (float)p2.x(), (float)p2.y(), -1.0f, 1.0f, 1.0f,
        (float)p1.x(), (float)p2.y(), -1.0f, 0.0f, 1.0f
    };

    unsigned int indices[] = { 0, 1, 2, 3 };

    mShaderProgram.setUniformValue("u_Color", 0.0f, 0.0f, 0.0f, 0);

    glBindVertexArray(mVAOArray[6]);

    glBindBuffer(GL_ARRAY_BUFFER, mVBOArray[6]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mEBOArray[2]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    // position attribute
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    // texture coord attribute
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);

    // load and create a texture
    // -------------------------
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, mTextureID);

    // set texture filtering parameters
    // 使用 GL_LINEAR_MIPMAP_LINEAR 的时候，必须调用  glGenerateMipmap 函数
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    // set the texture wrapping parameters
    // set texture wrapping to GL_REPEAT (default wrapping method)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

    int ot = glGetUniformLocation(mShaderProgram.programId(), "outTexture");
    if (ot < 0) return;
    glUniform1i(ot, 0);

    unsigned char *labelData = image.bits();
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, labelData);

    glDrawElements(GL_QUADS, 4, GL_UNSIGNED_INT, 0);
}

void WidgetPointView::drawLabels()
{
    // calc position
    QPointF p1 = mapToOpenGL(QPointF(0, 0));
    QPointF p2 = mapToOpenGL(QPointF(width(), height()));

    //qDebug() << "point " << p1 << p2 << textWidth << textHeight;

    float width = p2.x() - p1.x();
    float height = p2.y() - p1.y();

    //qDebug() << "w1 " << width << QString::number(qLn(width / 50.0) / qLn(5), 'f', 6);
    float space = qRound(qLn(width / 20.0) / qLn(5));
    space = qPow(5, space);

    float xPos = qCeil(p1.x() / space) * space;
    float yPos = qCeil(p1.y() / space) * space;

    int xLineSize = (int)qAbs(width / space) + 2;
    int yLineSize = (int)qAbs(height / space) + 2;
    int lineSize = xLineSize + yLineSize;

    //qDebug() << "inforation " << yPos << xPos << width << space << xLineSize << yLineSize;

    QImage image = createTextImgae(xPos, xLineSize, yPos, yLineSize, space, QColor(36, 36, 36));
    float textWidth = width * (96.0 / this->width());
    float textHeight = textWidth * -0.13963;

    // 计算网格位置
    float *vertices = new float[20 * lineSize];
    for (int i = 0; i < yLineSize; i++)
    {
        vertices[i * 20 + 0] = (float)p1.x();
        vertices[i * 20 + 1] = yPos;
        vertices[i * 20 + 2] = -1.0;
        vertices[i * 20 + 3] = 1.0;
        vertices[i * 20 + 4] = 1.0 - (float)i / lineSize;

        vertices[i * 20 + 5] = (float)p1.x();
        vertices[i * 20 + 6] = yPos + textHeight;
        vertices[i * 20 + 7] = -1.0;
        vertices[i * 20 + 8] = 1.0;
        vertices[i * 20 + 9] = 1.0 - (float)(i + 1) / lineSize;

        vertices[i * 20 +10] = (float)p1.x() + textWidth;
        vertices[i * 20 +11] = yPos + textHeight;
        vertices[i * 20 +12] = -1.0;
        vertices[i * 20 +13] = 0.0;
        vertices[i * 20 +14] = 1.0 - (float)(i + 1) / lineSize;

        vertices[i * 20 +15] = (float)p1.x() + textWidth;
        vertices[i * 20 +16] = yPos;
        vertices[i * 20 +17] = -1.0;
        vertices[i * 20 +18] = 0.0;
        vertices[i * 20 +19] = 1.0 - (float)i / lineSize;

        yPos = yPos - space;
    }

    for (int j = 0; j < xLineSize; j++)
    {
        float t1 = 1.0 - (float)(j + 1 + yLineSize) / lineSize;
        float t2 = 1.0 - (float)(j + yLineSize) / lineSize;

        vertices[(j + yLineSize) * 20 + 0] = xPos;
        vertices[(j + yLineSize) * 20 + 1] = (float)p2.y();
        vertices[(j + yLineSize) * 20 + 2] = -1.0;
        vertices[(j + yLineSize) * 20 + 3] = 1.0;
        vertices[(j + yLineSize) * 20 + 4] = t2;

        vertices[(j + yLineSize) * 20 + 5] = xPos;
        vertices[(j + yLineSize) * 20 + 6] = (float)p2.y() + textWidth;
        vertices[(j + yLineSize) * 20 + 7] = -1.0;
        vertices[(j + yLineSize) * 20 + 8] = 0.0;
        vertices[(j + yLineSize) * 20 + 9] = t2;

        vertices[(j + yLineSize) * 20 +10] = xPos - textHeight;
        vertices[(j + yLineSize) * 20 +11] = (float)p2.y() + textWidth;
        vertices[(j + yLineSize) * 20 +12] = -1.0;
        vertices[(j + yLineSize) * 20 +13] = 0.0;
        vertices[(j + yLineSize) * 20 +14] = t1;

        vertices[(j + yLineSize) * 20 +15] = xPos - textHeight;
        vertices[(j + yLineSize) * 20 +16] = (float)p2.y();
        vertices[(j + yLineSize) * 20 +17] = -1.0;
        vertices[(j + yLineSize) * 20 +18] = 1.0;
        vertices[(j + yLineSize) * 20 +19] = t1;

        xPos = xPos + space;
    }

    mShaderProgram.setUniformValue("u_Color", 0.0f, 0.0f, 0.0f, 0);
    glBindVertexArray(mVAOArray[1]);
    glBindBuffer(GL_ARRAY_BUFFER, mVBOArray[1]);
    glBufferData(GL_ARRAY_BUFFER, 4 * 20 * lineSize, vertices, GL_DYNAMIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mEBOArray[0]);
    unsigned int *indices = new unsigned int[4 * lineSize];
    for (int i = 0; i < 4 * lineSize; i++) indices[i] = i;
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, 4 * 4 * lineSize, indices, GL_DYNAMIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    // texture coord attribute
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);

    // load and create a texture
    // -------------------------
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, mTextureID);

    int ot = glGetUniformLocation(mShaderProgram.programId(), "outTexture");
    if (ot < 0) return;
    // 赋值为 0 是因为这里启用的纹理是 GL_TEXTURE0
    glUniform1i(ot, 0);

    unsigned char *labelData = image.bits();
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, labelData);

    // set texture filtering parameters
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    // set the texture wrapping parameters
    // set texture wrapping to GL_REPEAT (default wrapping method)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

    glDrawElements(GL_QUADS, 4 * lineSize, GL_UNSIGNED_INT, 0);

    delete [] vertices;
    delete [] indices;
}

void WidgetPointView::drawPoint()
{
    mShaderProgram.setUniformValue("u_Color", 0.0f, 0.7725f, 0.5254f, 1.0f);
    // 绘制点
    int pointNumber = mPointList.length();
    if (pointNumber == 0) return;
    float *vertices = new float[3 * pointNumber];
    int count = 0;
    for (int i = 0; i < pointNumber; i++)
    {
        if (!mPointList.value(i).valid()) continue;
        vertices[count * 3 + 0] = mPointList.value(i).x(mPointMode) - mOriginPointDerail.x(mPointMode);
        vertices[count * 3 + 1] = mPointList.value(i).y(mPointMode) - mOriginPointDerail.y(mPointMode);
        vertices[count * 3 + 2] = 0.0;
        count++;
    }
    if (count == 0)
    {
        delete [] vertices;
        return;
    }

    glBindVertexArray(mVAOArray[2]);
    glBindBuffer(GL_ARRAY_BUFFER, mVBOArray[2]);
    glBufferData(GL_ARRAY_BUFFER, 4 * 3 * count, vertices, GL_DYNAMIC_DRAW);

    // position attribute
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);

    glEnableVertexAttribArray(0);
    glPointSize(6);
    glDrawArrays(GL_POINTS, 0, count);
    glDisableVertexAttribArray(0);

    delete [] vertices;
}

void WidgetPointView::drawHighlightPoint()
{
    mShaderProgram.setUniformValue("u_Color", 0.9f, 0.3f, 0.1f, 1.0f);
    // 绘制点
    int pointNumber = mPointList.length();
    if (pointNumber == 0) return;
    float *vertices = new float[3 * pointNumber];
    int count = 0;
    for (int i = 0; i < pointNumber; i++)
    {
        if (!mPointList.value(i).valid()) continue;
        if (!mPointList.value(i).highlight()) continue;
        vertices[count * 3 + 0] = mPointList.value(i).x(mPointMode) - mOriginPointDerail.x(mPointMode);;
        vertices[count * 3 + 1] = mPointList.value(i).y(mPointMode) - mOriginPointDerail.y(mPointMode);;
        vertices[count * 3 + 2] = 0.0;
        count++;
    }
    if (count == 0)
    {
        delete [] vertices;
        return;
    }

    glBindVertexArray(mVAOArray[3]);
    glBindBuffer(GL_ARRAY_BUFFER, mVBOArray[3]);
    glBufferData(GL_ARRAY_BUFFER, 4 * 3 * count, vertices, GL_DYNAMIC_DRAW);

    // position attribute
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);

    glEnableVertexAttribArray(0);
    glPointSize(6);
    glDrawArrays(GL_POINTS, 0, count);
    glDisableVertexAttribArray(0);

    delete [] vertices;
}

void WidgetPointView::drawLine()
{
    mShaderProgram.setUniformValue("u_Color", 0.3f, 0.6f, 0.9f, 1.0f);
    int pointNumber = mPointList.length();
    int count = 0;
    for (int i = 0; i < pointNumber; i++)
    {
        if (!mPointList.value(i).valid()) continue;
        count++;
    }
    if (count == 0) return;

    glBindVertexArray(mVAOArray[2]);
    glBindBuffer(GL_ARRAY_BUFFER, mVBOArray[2]);

    // position attribute
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);

    glEnableVertexAttribArray(0);
    glDrawArrays(GL_LINE_STRIP, 0, count);
    glDisableVertexAttribArray(0);
}

void WidgetPointView::drawBox()
{
    if (!mSelectMode || !mMousePressed) return;

    mShaderProgram.setUniformValue("u_Color", 0.9882f, 0.5686f, 0.3254f, 1.0f);

    unsigned int indices[] = { 0, 1, 1, 2, 2, 3, 3, 0 };

    // 计算 方框位置
    QPointF p1 = mapToOpenGL(mLastMousePosition);
    QPointF p2 = mapToOpenGL(mCurrentMousePosition);

    float x1 = p1.x();
    float y1 = p1.y();
    float x2 = p2.x();
    float y2 = p2.y();

    mRectSelect = QRectF(qMin(x1, x2) + mOriginPointDerail.x(mPointMode), qMin(y1, y2) + mOriginPointDerail.y(mPointMode), qAbs(x1 - x2), qAbs(y1 - y2));

    glBindVertexArray(mVAOArray[5]);
    float vertices[] = { x2, y1, 0.0f, x2, y2, 0.0f, x1, y2, 0.0f, x1, y1, 0.0f };
    glBindBuffer(GL_ARRAY_BUFFER, mVBOArray[5]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mEBOArray[1]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_DYNAMIC_DRAW);

    glEnableVertexAttribArray(0);
    glLineWidth(1);
    glEnable(GL_LINE_SMOOTH);
    glHint(GL_LINE_SMOOTH_HINT,GL_NICEST);
    glDrawElements(GL_LINES, 8, GL_UNSIGNED_INT, nullptr);
    glDisableVertexAttribArray(0);
}

QPointF WidgetPointView::mapToOpenGL(const QPointF &point)
{
    float x = (width() - mTextureWidth) / 2.0;
    float y = (height() - mTextureHeight) / 2.0;
    float x1 = 2.0f * (point.x() - x) / mTextureWidth - 1.0f;
    float y1 = 1.0f - (2.0f * (point.y() - y) / mTextureHeight);

    x1 = x1 / mViewZoom - mXOffset;
    y1 = y1 / mViewZoom - mYOffset;

    return QPointF(x1, y1);
}

QRectF WidgetPointView::boundingRect()
{
    double minX = 0.0, minY = 0.0, maxX = 0.0, maxY = 0.0;

    // 计算 底图的范围
    if (mTiffDetail.valid && mShowTiffStatues && (mPointMode == 0))
    {
        minX = mTiffDetail.topleftx;
        maxX = mTiffDetail.bottomrightx;
        minY = mTiffDetail.bottomrighty;
        maxY = mTiffDetail.toplefty;
    }

    if (mPointList.isEmpty())
    {
        minX = minX - mOriginPointDerail.x(mPointMode);
        minY = minY - mOriginPointDerail.y(mPointMode);
        maxX = maxX - mOriginPointDerail.x(mPointMode);
        maxY = maxY - mOriginPointDerail.y(mPointMode);
        return QRectF{ minX, minY, maxX - minX, maxY - minY };
    }

    mOriginPointDerail = mPointList.at(0);

    if (!mTiffDetail.valid || !mShowTiffStatues  || (mPointMode != 0))
    {
        minX = mOriginPointDerail.x(mPointMode); maxX = mOriginPointDerail.x(mPointMode);
        minY = mOriginPointDerail.y(mPointMode); maxY = mOriginPointDerail.y(mPointMode);
    }

    for (auto &point: mPointList)
    {
        if (!point.valid()) continue;
        minX = qMin(point.x(mPointMode), minX);
        maxX = qMax(point.x(mPointMode), maxX);
        minY = qMin(point.y(mPointMode), minY);
        maxY = qMax(point.y(mPointMode), maxY);
    }

    minX = minX - mOriginPointDerail.x(mPointMode);
    minY = minY - mOriginPointDerail.y(mPointMode);
    maxX = maxX - mOriginPointDerail.x(mPointMode);
    maxY = maxY - mOriginPointDerail.y(mPointMode);

    return QRectF{ minX, minY, maxX - minX, maxY - minY };
}

QImage WidgetPointView::createTextImgae(double xPos, double xLineSize, double yPos, double yLineSize, double space, QColor fontColor)
{
    QFont font("Times New Roman", 10);
    QFontMetrics fontMetrics(font);
    QString temp = "  000° 00′ 00.0000″ E ";
    QRect bounding = fontMetrics.boundingRect(temp);
    QImage image(bounding.width(), bounding.height() * (xLineSize + yLineSize), QImage::Format_RGBA8888);
    image.fill(QColor(0, 0, 0, 0));

    QPainter painter(&image);
    painter.setRenderHints(QPainter::TextAntialiasing | QPainter::Antialiasing);
    painter.setFont(font);
    painter.setPen(fontColor);

    xPos += mOriginPointDerail.x(mPointMode);
    yPos += mOriginPointDerail.y(mPointMode);

    if (mPointMode != 0)
    {
        yPos = yPos / 100000.0;
        space = space / 100000.0;
    }

    for (int i = 0; i < yLineSize; i++)
    {
        double value = qAbs(yPos - space * i);
        double d = qFloor(value);
        double m = qFloor((value - d) * 60);
        double s = (value - d - m / 60.0) * 60;
        QString dStr = ("000" + QString::number(qAbs(d))).right(3);
        QString mStr = ("00" + QString::number(qAbs(m))).right(2);
        QString sStr = ("00" + QString::number(qAbs(s), 'f', 4)).right(7);
        QString flagStr = (yPos - space * i < 0) ? ((mPointMode == 1) ? "W" : "S") : ((mPointMode == 1) ? "E" : "N");
        QString text = QString("%1° %2′ %3″ %4").arg(dStr, mStr, sStr, flagStr);
        painter.drawText(QRect(0, bounding.height() * i, image.width(), bounding.height()), Qt::AlignCenter, text);
    }

    if (mPointMode == 0)
    {
        for (int j = 0; j < xLineSize; j++)
        {
            double value = qAbs(xPos + space * j);
            double d = qFloor(value);
            double m = qFloor((value - d) * 60);
            double s = (value - d - m / 60.0) * 60;
            QString dStr = ("000" + QString::number(qAbs(d))).right(3);
            QString mStr = ("00" + QString::number(qAbs(m))).right(2);
            QString sStr = ("00" + QString::number(qAbs(s), 'f', 4)).right(7);
            QString flagStr = (xPos + space * j < 0) ? "W" : "E";
            QString text = QString("%1° %2′ %3″ %4").arg(dStr, mStr, sStr, flagStr);
            painter.drawText(QRect(0, bounding.height() * (yLineSize + j), image.width(), bounding.height()), Qt::AlignCenter, text);
        }
    }
    else
    {
        for (int j = 0; j < xLineSize; j++)
        {
            double value = qAbs(xPos + space * 100000 * j);
            QString text = QDateTime::fromSecsSinceEpoch(value).toString("yyyy-MM-dd hh:mm:ss");
            painter.drawText(QRect(0, bounding.height() * (yLineSize + j), image.width(), bounding.height()), Qt::AlignCenter, text);
        }
    }

    painter.end();
    //image.save("big_one.png");

    return image.mirrored(true, true);
}

void WidgetPointView::highlightPoint()
{
    int pointNumber = mPointList.length();
    for (int i = 0; i < pointNumber; i++)
    {
        if (!mPointList.value(i).valid()) continue;
        QPointF point = QPointF(mPointList.value(i).x(mPointMode), mPointList.value(i).y(mPointMode));
        mPointList[i].setHighlight(mRectSelect.contains(point));
    }
    update();
}

void WidgetPointView::slot_parse_file_result(const QString &path, const QList<PointDetail> &result)
{
    if (!mShaderProgramLinked)
    {
        emit AppSignal::getInstance()->sgl_occur_system_error("请检查设备独立显卡状态");
        return;
    }
    Q_UNUSED(path);
    mPointList.append(result);
    focusProp();
}

void WidgetPointView::slot_parse_tiff_result(const TiffDetail &result)
{
    if (!mShaderProgramLinked)
    {
        emit AppSignal::getInstance()->sgl_occur_system_error("请检查设备独立显卡状态");
        return;
    }
    mTiffDetail = result;
    focusProp();
}
